import { getEntityById, globeCollection } from '../scene/map_collection.js'
import DataTypeEnum from '../enum/data_type_enum.js'

/**
 * 检查给定值是否存在且非空。
 *
 * @param {*} value - 需要检查的值，可以是任意类型。
 *
 * @returns {boolean} 如果值存在、非空字符串、非null、非undefined（对于数字类型，还检查其是否不是NaN），则返回true；否则返回false。
 *
 * @example
 * console.log(isExist(0)); // true
 * console.log(isExist('')); // false
 * console.log(isExist(null)); // false
 * console.log(isExist(undefined)); // false
 * console.log(isExist(3.14)); // true
 * console.log(isExist(NaN)); // false
 */
function isExist(value) {
	if (typeof value === 'number') {
		return !isNaN(value)
	}
	return value !== null && value !== '' && value !== void 0
}

/**
 * 判断给定的URL字符串是绝对路径还是相对路径。
 *
 * @param {string} url - 需要判断的URL字符串。
 * @returns {boolean} - 如果URL是绝对路径返回true，否则返回false。
 *
 * @example
 * console.log(isAbsoluteURL('http://example.com/path');     // 输出: true
 * console.log(isAbsoluteURL('//example.com/path');           // 输出: true
 * console.log(isAbsoluteURL('/relative/path'));               // 输出: true
 * console.log(isAbsoluteURL('relative/path'));                 // 输出: false
 * console.log(isAbsoluteURL('./relative/path'));              // 输出: false
 * console.log(isAbsoluteURL('../relative/path'));            // 输出: false
 */
function isAbsoluteURL(url) {
	/**
	 * 正则表达式匹配规则：
	 * - 开头以http://或https://表示绝对URL。
	 * - 或者以//开头，表示协议继承的绝对URL。
	 * - 排除以./或../开头的字符串，因为它们表示相对路径。
	 */
	const absolutePattern = /^(http|https):\/\/|^(?![.\/])/i
	return absolutePattern.test(url)
}

/**
 * 获取绝对路径
 *
 * @param {string} relativePath - 相对路径字符串，用于转换为绝对路径。
 * @param {function} [cb] - 可选的回调函数，当提供时，会将计算出的绝对路径作为参数调用该函数。
 * @returns {string} - 计算出的绝对路径。
 *
 * @throws {Error} - 如果 `relativePath` 不是字符串类型，则抛出错误。
 *
 * @example
 * // 异步使用示例
 * getAbsolutePath('path/to/file', function(url) {
 *   console.log(url);
 * });
 *
 * @example
 * // 同步使用示例
 * const url = getAbsolutePath('path/to/file');
 * console.log(url);
 */
function getAbsolutePath(relativePath, cb) {
	if (typeof relativePath !== 'string') {
		throw new Error('relativePath 必须为字符串')
	}
	if (!SSmap.getAbsolutePath) throw new Error('客户端API')

	const url = SSmap.getAbsolutePath(relativePath)

	if (typeof cb === 'function') {
		cb(url)
	}

	return url
}

/**
 * 将多维数组转换为SSmap.Vector3对象列表。每个元素应为包含经度（lng）、纬度（lat）和可选高度（alt）的数组。
 * 经纬度必须有效，否则将使用提供的坐标创建一个Vector3。如果坐标无效，则返回的Vector3将仅包含原始坐标。
 *
 * @param {Array<Array<Array<[number, number, number?]>>>} list - 一个3维数组，其中每个子数组包含一对或三对经度、纬度和高度坐标。
 * @returns {SSmap.Vector3[]} 返回一个由SSmap.Vector3对象组成的数组，表示输入坐标。
 */
function arrayToVector3(list) {
	return list
		.map((range) => {
			return range.map((location) => {
				return location.map(([lng, lat, alt = 0]) => {
					return isValidLngLat({ lng, lat })
						? SSmap.Cartesian3.fromDegrees(lng, lat, alt).toVector3()
						: SSmap.Vector3.create(lng, lat, alt)
				})
			})
		})
		.reduce((acc, curr) => acc.concat(curr), [])
}

function lngLatToVector3({ lng, lat, alt = 0 }, callback) {
	const vector3 = SSmap.Cartesian3.fromDegrees(lng, lat, alt).toVector3()
	const result = { x: vector3.x, y: vector3.y, z: vector3.z }
	if (typeof callback === 'function') {
		callback(result)
	}
}

/**
 * 验证经纬度是否有效
 * @param {Object} coords - 一个包含经度（lng）和纬度（lat）的对象
 * @returns {boolean} - 如果经纬度在有效范围内则返回true，否则返回false
 *
 * @example
 * // 示例用法：
 * console.log(isValidLngLat({ lng: 120.75, lat: 31.21 })); // 应当输出：true
 * console.log(isValidLngLat({ lng: 200.75, lat: 31.21 })); // 应当输出：false，因为经度超出范围
 */
function isValidLngLat({ lng, lat }) {
	// 经度检查：-180 <= lng <= 180
	const isLngValid = lng >= -180 && lng <= 180

	// 纬度检查：-90 <= lat <= 90
	const isLatValid = lat >= -90 && lat <= 90

	// 如果经度和纬度都在其有效范围内，则认为坐标有效
	return isLngValid && isLatValid
}
function resetBlink(layer) {
	const target = getEntityById(layer.id)
	if (!target) throw new Error('target not found for resetBlink')
	if (Array.isArray(target)) {
		target.forEach((j) => {
			'enabled' in j && (j.enabled = true)
			'show' in j && (j.show = true)
			if (j.tag !== '' && j.tag !== undefined) {
				let { altitude } = JSON.parse(j.tag)
				if (j.dataType === 'polyline3D') {
					j.setAltitude(Number(altitude))
					// j.setAltitudeMethod(SSmap.AltitudeMethod[altitudeMethod])
					j.objectName = 'draw'
					j.end && j.end()
					j.alpha = 0.9
				}
			}
		})
	} else {
		'enabled' in target && (target.enabled = true)
		'show' in target && (target.show = true)
		if (target.tag !== '' && target.tag !== undefined) {
			let { altitude } = JSON.parse(target.tag)
			if (target.dataType === 'polyline3D') {
				target.setAltitude(Number(altitude))
				target.objectName = 'draw'
				target.end && target.end()
				target.alpha = 0.9
			}
		}
	}
}
function blink(layers) {
	layers.forEach((i) => {
		const target = getEntityById(i.id)
		if (!target) throw new Error('target not found for blink')

		if (Array.isArray(target)) {
			target.forEach((j) => {
				if (j.tag !== '' && j.tag !== undefined) {
					let { altitude } = JSON.parse(j.tag)
					if (j.dataType === 'polyline3D' && j.objectName === 'draw') {
						j.setAltitude(Number(altitude) + 5)
						j.objectName = 'noDraw'
						// j.redraw && j.redraw()
						j.end && j.end()
					}
					j.alpha = j.alpha >= 0.9 ? 0.01 : 0.9
				} else {
					'enabled' in j && (j.enabled = !j.enabled)
					'show' in j && (j.show = !j.show)
				}
			})
		} else {
			if (target.tag !== '' && target.tag !== undefined) {
				let { altitude } = JSON.parse(target.tag)
				if (target.dataType === 'polyline3D' && target.objectName === 'draw') {
					target.setAltitude(Number(altitude) + 5)
					target.objectName = 'noDraw'
					// target.redraw && target.redraw()
					target.end && target.end()
				}
				target.alpha = target.alpha >= 0.9 ? 0.01 : 0.9
			} else {
				'enabled' in target && (target.enabled = !target.enabled)
				'show' in target && (target.show = !target.show)
			}
		}
	})
}

function _offsetToposition(Cartographic, height, opt){
	opt = opt || {};
	let nowpitch = Math.abs(opt.pitch || -45);
	let newpitch = null;
	if (nowpitch % 90 == 0 && nowpitch != 0) {
		newpitch = 90;
	} else if (nowpitch % 90 <= 34) {
		newpitch = 34;
	} else {
		newpitch = nowpitch % 90; //默认-45度
	}
	let multiple = Math.abs(((newpitch / 0.01) * 0.00023).toFixed(2));
	Cartographic.height = multiple * height; //0.00023=0.01度
	let nowposition = Cartographic.toVector3();
	let multipleone = Number((multiple - 2.15).toFixed(2));
	nowposition = vector3Offset(nowposition, {
		//offsetY: Math.cos(AngleToRadian(Number(opt.pitch))) * height,
		offsetY: multipleone * height,
	});
	return nowposition;
}

/**
 * 根据给定的偏移量计算一个点在三维空间中的新位置。
 * 此函数主要用于在具有全局视图的场景中，对点进行平移操作。
 * 它首先将点转换为三维坐标系中的向量，然后应用偏移量，最后返回新的位置向量。
 *
 * @param {Object} point - 一个表示点的对象，该对象应具有转换为三维坐标的方法。
 * @param {Object} options - 一个包含偏移量的对象，可以指定x、y、z三个方向上的偏移量。
 * @param {number} options.offsetX - x轴方向上的偏移量，默认为0。
 * @param {number} options.offsetY - y轴方向上的偏移量，默认为0。
 * @param {number} options.offsetZ - z轴方向上的偏移量，默认为0。
 * @returns {Object} - 返回计算后的新位置向量，如果全局视图不存在，则不进行计算并返回undefined。
 */
function vector3Offset(point, { offsetX = 0, offsetY = 0, offsetZ = 0 }) {
	// 检查是否存在全局视图对象
	if (GlobalViewer) {
		// 创建一个代表偏移量的三维向量
		let vec3 = SSmap.Vector3.create(offsetX, offsetY, offsetZ)
		// 将点的坐标转换为全局三维坐标系中的向量
		let localToWorld = GlobalViewer.scene.globe.ellipsoid.eastNorthUpToFixedFrame(
			point.toCartesian3()
		)
		// 将偏移量向量应用到点的坐标上，得到新的位置向量
		return SSmap.Matrix4.multiplyByVector3(localToWorld, vec3)
	}
}

/**
 * 根据给定的数据类型获取特征属性。
 *
 * 此函数旨在根据不同的数据类型，通过调用相应的函数来获取当前选中的特征及其属性。
 * 支持的数据类型包括GeoJsonModel、GeoJsonPolylineLayer和ProjectionDataSource。
 * 如果提供了回调函数，则在获取属性后将其作为参数调用。
 *
 * @param {Object} param0 包含数据类型的对象。
 * @param {function} cb 可选的回调函数，用于处理获取的属性结果。
 * @returns {Object} 返回一个对象，包含特征的所有属性。
 */
function getAttribute({ type, id }, cb) {
	// 定义一个函数映射表，根据不同的数据类型，返回相应的特征获取方法。
	const fn = {
		[DataTypeEnum.GeoJsonModel]: () => SSmap.GeoJsonModel.getSelectedFeature(),
		[DataTypeEnum.GeoJsonPolylineLayer]: () => window.viewer.scene.getFeatureByMouse(),
		[DataTypeEnum.ProjectionDataSource]: () =>
			globeCollection.projectionLayer.getFeatureByMouse(),
		[DataTypeEnum.Label3D]: () => window.viewer.scene.getFeatureByMouse(),
		[DataTypeEnum.Tileset]: () => window.viewer.scene.getFeatureByMouse(),
		[DataTypeEnum.Polygon3D]: () => window.viewer.scene.getFeatureByMouse(),
		[DataTypeEnum.GeoJsonPointLayer]: () => {
			const feature = window.viewer.scene.getFeatureByMouse()
			const geoJsonPointLayer = SSmap.GeoJsonPointLayer.getSelect(feature)
			if (!geoJsonPointLayer) return
			const id = feature.getProperty('id')
			const keys = geoJsonPointLayer.getKeys()
			const size = keys.size()
			const result = {}
			for (let i = 0; i < size; i++) {
				const key = keys.get(i)
				result[key] = geoJsonPointLayer.getPropertie(id, key)
			}
			return result
		},
		[DataTypeEnum.GeoJsonPolygonLayer]: () => {
			const feature = window.viewer.scene.getFeatureByMouse()
			const geoJsonPolygonLayer = SSmap.GeoJsonPolygonLayer.getSelect(feature)
			if (!geoJsonPolygonLayer) return
			const id = feature.getProperty('id')
			const keys = geoJsonPolygonLayer.getKeys()
			const size = keys.size()
			const result = {
				index: id,
			}

			for (let i = 0; i < size; i++) {
				const key = keys.get(i)
				result[key] = geoJsonPolygonLayer.getPropertie(id, key)
			}
			return result
		},
	}

	// 根据数据类型从映射表中获取特征获取函数，并执行该函数以获取特征。
	const feature = fn[type] && fn[type]()

	if (type === DataTypeEnum.GeoJsonPointLayer) {
		const result = feature
		if (typeof cb === 'function') cb(result)
		return result
	} else if (type === DataTypeEnum.GeoJsonPolygonLayer) {
		const result = feature
		if (typeof cb === 'function') cb(result)
		return result
	}
	// 如果没有获取到特征，则直接返回。
	// if (!feature) throw new Error('no feature selected')
	if (!feature) return cb && cb(null)

	// 获取特征的所有属性名。
	const propertyNames = feature.propertyNames()
	// 获取属性名的数量。
	const size = propertyNames.size()

	// 初始化一个对象，用于存储属性名和对应的属性值。
	const result = {}
	// 遍历属性名集合，将每个属性名及其值添加到结果对象中。
	for (let i = 0; i < size; i++) {
		const key = propertyNames.get(i)
		result[key] = feature.getProperty(key)
	}

	// 如果提供了回调函数，则调用回调函数并传入属性结果。
	if (typeof cb === 'function') cb(result)

	// 返回属性结果对象。
	return result
}

function getAttributeByTileset() {
	const feature = window.viewer.scene.getFeatureByMouse()
	window.viewer.scene.setSelectedFeature(feature)
	let nameList = feature.propertyNames()
	let size = nameList.size()
	const result = {}
	for (let i = 0; i < size; i++) {
		let key = nameList.get(i)
		result[key] = feature.getProperty(key)
	}
}

/**
 * 计算数组的维度
 *
 * @param {Array} arr - 要计算维度的数组
 * @param {number} [num=0] - 当前的维度深度，默认为0
 * @returns {number} 返回数组的维度深度
 */
function getArrayDimensional(arr, num = 0) {
	// 检查当前元素是否为数组，如果是，则维度深度加1
	if (arr instanceof Array) {
		num++
	}
	let newNum = 0
	// 遍历数组中的每个元素，递归计算每个元素的维度
	for (let i = 0; i < arr.length; i++) {
		let newArray = arr[i]
		newNum = getArrayDimensional(newArray, num)
	}
	// 如果当前元素的维度大于已知的最大维度，则更新最大维度
	if (newNum > num) num = newNum
	return num
}

/**
 * 函数节流。
 * 在一定时间内只允许调用指定函数一次，常用于控制频繁触发的事件，如滚动事件、窗口大小调整事件等。
 *
 * @param {Function} func 要节流的函数。
 * @param {number} wait 节流间隔时间，默认为500毫秒。
 * @returns {Function} 返回一个节流后的函数。
 */
function throttle(func, wait = 500) {
	// 用于存储节流函数的定时器ID
	let timeout = null
	// 用于记录上一次函数调用的时间
	let previous = 0

	// 返回一个节流函数
	return function () {
		// 保存当前上下文和参数，以便在定时器中使用
		const context = this
		const args = arguments
		// 获取当前时间
		const now = new Date().getTime()

		// 计算距离上一次调用的时间间隔
		// 计算从上一次调用到现在过去了多少时间
		const remaining = wait - (now - previous)

		// 如果时间间隔已经超过等待时间，或者小于等于0，表示可以立即调用函数
		// 如果remaining为负数，表示已经到达可以执行的时机
		if (remaining <= 0 || remaining > wait) {
			// 如果存在定时器，清除它
			if (timeout) {
				clearTimeout(timeout)
				timeout = null
			}
			// 更新上一次调用的时间为当前时间
			previous = now
			// 执行原函数
			func.apply(context, args)
		} else {
			// 如果不存在定时器，设置一个定时器，在剩余时间后调用函数
			if (!timeout) {
				// 首次调用或者上一次执行完毕后，等待期间再次调用，设置新的timeout
				timeout = setTimeout(function () {
					// 更新上一次调用的时间为当前时间
					previous = now
					// 清除定时器ID，防止重复设置定时器
					timeout = null
					// 执行原函数
					func.apply(context, args)
				}, remaining)
			}
		}
	}
}

/**
 * 计算目标点的集合。
 * 根据中心点和半径，在球面上计算出一系列目标点的地理坐标和三维向量。
 *
 * @param {SSmap.Cartesian3} center - 地球表面上的中心点坐标。
 * @param {number} radius - 以中心点为圆心的圆的半径。
 * @returns {Object} 返回一个对象，包含两个数组：cartographic和vector3，分别存储目标点的地理坐标和三维向量。
 */
function calculatingTargetPoints(center, radius, dataType, callBack) {
	// 获取当前场景的球体对象
	const globe = window.viewer.scene.globe
	// 初始化用于存储地理坐标的数组
	const cartographic = []
	// 初始化用于存储三维向量的数组
	const vector3 = []

	// 创建Web Mercator投影对象
	const webMercatorProjection = new SSmap.WebMercatorProjection(globe.ellipsoid)
	if (dataType === 'cartographic') {
		// 如果数据类型是'cartographic'，则将中心点转换为地理坐标
		center = SSmap.Cartographic.fromDegrees(
			center.lng,
			center.lat,
			center.alt || 0
		).toCartesian3()
	}
	// 将中心点从三维坐标转换为Web Mercator投影坐标
	const viewPointWebMercator = webMercatorProjection.project(
		SSmap.Cartographic.fromCartesian(center)
	)

	// 遍历360度，计算每个角度对应的目标点
	for (let i = 0; i < 360; i++) {
		// 根据当前角度和半径，计算目标点的Web Mercator投影坐标
		let p = SSmap.Cartesian3.create(
			viewPointWebMercator.x + radius * Math.cos((i * Math.PI) / 180),
			viewPointWebMercator.y + radius * Math.sin((i * Math.PI) / 180),
			viewPointWebMercator.z
		)

		// 将Web Mercator投影坐标转换回地理坐标
		p = webMercatorProjection.unproject(p)

		// 从地理坐标转换为三维向量
		const c = p.toCartesian3().toCartographic().toDegrees()
		c.height < 0 ? (c.height = 0) : ''

		const v = p.toCartesian3().toCartographic().toVector3()

		// 将地理坐标和三维向量添加到对应的数组中
		cartographic.push(c)
		vector3.push(v)
	}
	callBack && callBack({ cartographic, vector3 })
	// 返回包含地理坐标和三维向量的数组的对象
	return { cartographic, vector3 }
}

/**
 * 根据两个点的信息获取矩形区域的相关信息。
 * @param {Object} point1 - 第一个点的坐标信息，包含x、y、z属性。
 * @param {Object} point2 - 第二个点的坐标信息，包含x、y、z属性。
 * @returns {Object} 返回一个对象，包含矩形的顶点坐标和经纬度位置信息。
 */
function getRectangleInfo(point1, point2) {
	// 初始化结果对象，包含点的数组、位置的数组和矩形对象
	const result = {
		points: [], // vector3 x y z,
		positions: [], // 经纬度坐标
		rectangle: null,
	}
	// 创建一个初始矩形对象，经纬度坐标为0,0的矩形
	const rectangle = SSmap.Rectangle.fromDegrees(0, 0, 0, 0)
	// 根据点1的坐标创建Vector3对象
	const p1 = SSmap.Vector3.create(point1.x, point1.y, point1.z)
	// 根据点2的坐标创建Vector3对象
	const p2 = SSmap.Vector3.create(point2.x, point2.y, point2.z)
	// 将点1和点2的坐标信息合并到矩形中
	rectangle.combinePoint(p1.toCartesian3().toCartographic())
	rectangle.combinePoint(p2.toCartesian3().toCartographic())

	// 计算矩形的四个顶点：西南、西北、东北、东南
	const sw = rectangle.southwest().toVector3()
	const nw = rectangle.northwest().toVector3()
	const ne = rectangle.northeast().toVector3()
	const se = rectangle.southeast().toVector3()
	// 将顶点坐标添加到结果的points数组中
	result.points.push(sw)
	result.points.push(nw)
	result.points.push(ne)
	result.points.push(se)

	// 再次将顶点坐标合并到矩形中，以确保矩形的准确计算
	rectangle.combinePoint(sw.toCartesian3().toCartographic())
	rectangle.combinePoint(nw.toCartesian3().toCartographic())
	rectangle.combinePoint(ne.toCartesian3().toCartographic())
	rectangle.combinePoint(se.toCartesian3().toCartographic())
	// 将矩形对象设置到结果对象中
	result.rectangle = rectangle

	// 计算并获取每个顶点的经纬度位置
	const positionSW = sw.toCartesian3().toCartographic().toDegrees()
	const positionNW = nw.toCartesian3().toCartographic().toDegrees()
	const positionNE = ne.toCartesian3().toCartographic().toDegrees()
	const positionSE = se.toCartesian3().toCartographic().toDegrees()
	// 将顶点的经纬度位置添加到结果的positions数组中
	result.positions.push([positionSW.longitude, positionSW.latitude])
	result.positions.push([positionNW.longitude, positionNW.latitude])
	result.positions.push([positionNE.longitude, positionNE.latitude])
	result.positions.push([positionSE.longitude, positionSE.latitude])

	// 返回包含矩形信息的结果对象
	return result
}

/**
 * 获取当前经纬度的射线 海拔值
 * @param {Object} carto - 经纬度对象，包含longitude和latitude属性。
 * @returns {number || void} 返回当前经纬度点的海拔值。
 */
function getTestHeight(carto) {
	let { longitude, latitude } = carto
	let v1 = SSmap.Cartographic.fromDegrees(longitude, latitude, 0).toVector3()
	let v2 = SSmap.Cartographic.fromDegrees(longitude, latitude, 1000).toVector3()
	let ray = SSmap.Ray.create(v2, SSmap.Vector3.subtract(v1, v2).normalize())
	let hit = new SSmap.RaycastHit()

	if (hit === null || hit === undefined) return

	let result = null
	if (window.viewer.scene.raycast(ray, hit)) {
		// console.log('hit')
		result = hit.point.toCartographic()
	}
	hit.delete()
	// console.log('海拔', result.height)
	return result == null ? 0.0 : result.height
}

function calculateDistance({ pointA, pointB }, cb = null) {
	// 根据点A的坐标创建起点
	let startPoint =
		typeof pointA === 'object'
			? SSmap.Cartesian3.fromDegrees(pointA.lng, pointA.lat, pointA.alt).toVector3()
			: null

	// 根据点B的坐标创建终点
	let endPoint =
		typeof pointB === 'object'
			? SSmap.Cartesian3.fromDegrees(pointB.lng, pointB.lat, pointB.alt).toVector3()
			: null

	// 初始化距离结果
	let resultDistance = null

	// 如果起点和终点都存在，则计算距离
	if (startPoint && endPoint) {
		resultDistance = startPoint.distance(endPoint)
	}

	// 如果提供了回调函数，则调用回调函数并传入距离结果
	if (typeof cb === 'function') {
		cb(resultDistance)
	}

	// 返回距离结果
	return resultDistance
}

function setTileset({ id, list }) {
	const tileset = globeCollection.tileset[id]
	const style = new SSmap.TilesetStyle()
	style.show = function (feature) {
		if (Array.isArray(list) && list.length) {
			const name = feature.getProperty('name')
			return list.includes(name)
		} else {
			return false
		}
	}
	tileset.style = style
	tileset.markStyleDirty()
}

function getFloor({ id }, cb) {
	const tileset = globeCollection.tileset[id]
	let count = 0
	tileset.contentLoaded(
		() => {
			count++
			if (count === 13) {
				const bimPullOut = new SSmap.BIMPullOut(tileset)
				const floors = bimPullOut.floors()
				const size = floors.size()
				const result = []
				for (let i = 0; i < size; i++) {
					let floorName = floors.get(i)
					console.log(floorName)
					result.push(floorName)
				}
				globeCollection.bimPullOut[id] = bimPullOut
				if (typeof cb === 'function') cb(result)
			}
		}
		// throttle(() => {

		// }, 1000)
	)
}

function moveFloor({ id, key }) {
	resetFloor({ id })
	const bimPullOut = globeCollection.bimPullOut[id]
	const { xOffset, yOffset } = bimFloorOffset(200, 40)
	bimPullOut.move(key, SSmap.Vector3.create(0, 0, 70))
	// setTimeout(() => {
	// 	bimPullOut.reset()
	// })
}

function resetFloor({ id }) {
	const bimPullOut = globeCollection.bimPullOut[id]
	bimPullOut.reset()
}
function bimFloorOffset(angle, distance) {
	let xOffset = Math.sin((angle * Math.PI) / 180) * distance
	let yOffset = Math.cos((angle * Math.PI) / 180) * distance
	return { xOffset, yOffset }
}

/**
 * @description 计算中心点
 * @param points
 * @param callback
 * @return {{lng, alt, lat}}
 */
function computeCenterPoint(points, callback = null) {
	console.log(points, 'points')
	let PVX = Number.MAX_VALUE // x的最大值
	let PVY = Number.MAX_VALUE // y的最大值
	let PVZ = Number.MAX_VALUE // z的最大值
	let NVX = -Number.MAX_VALUE // -x的最大值
	let NVY = -Number.MAX_VALUE // -y的最大值
	let NVZ = -Number.MAX_VALUE // -z的最大值
	if (points.length === 0) {
		console.error('没有点，无法计算')
	} else if (points.length === 1) {
		console.error('只有一个点，无法计算')
	} else {
		for (let i = 0; i < points.length; i++) {
			if (points[i].x < PVX) {
				PVX = points[i].x
			}
			if (points[i].y < PVY) {
				PVY = points[i].y
			}
			if (points[i].z < PVZ) {
				PVZ = points[i].z
			}
			if (points[i].x > NVX) {
				NVX = points[i].x
			}
			if (points[i].y > NVY) {
				NVY = points[i].y
			}
			if (points[i].z > NVZ) {
				NVZ = points[i].z
			}
		}

		let l = SSmap.Vector3.create((NVX + PVX) / 2, (NVY + PVY) / 2, (NVZ + PVZ) / 2)

		callback &&
			callback({
				lng: l.x,
				lat: l.y,
				alt: l.z,
			})

		return {
			lng: l.x,
			lat: l.y,
			alt: l.z,
		}
	}
}

function vector3ToGeoPoint({ x, y, z }, cb) {
	const vector3 = SSmap.Vector3.create(x, y, z)
	const cartographic = vector3.toCartographic().toDegrees()
	const result = {
		lng: cartographic.lon,
		lat: cartographic.lat,
		alt: cartographic.height,
	}
	if (typeof cb === 'function') cb(result)
	return cartographic
}
function worldToScreen({ x, y, z }, cb) {
	const position = window.viewer.scene.mainCamera.worldToScreenPoint(
		SSmap.Cartographic.fromDegrees(x, y, z || 0).toVector3()
	)
	cb && cb(position.x, position.y)
}

function getGeoPointDistance({ startPoint, endPoint }, cb) {
	const p1 = SSmap.Cartographic.fromDegrees(
		startPoint.lng,
		startPoint.lat,
		startPoint.alt
	).toVector3()
	const p2 = SSmap.Cartographic.fromDegrees(
		endPoint.lng,
		endPoint.lat,
		endPoint.alt
	).toVector3()
	const result = p1.distance(p2)
	if (typeof cb === 'function') cb(result)
	return result
}

export {
	isExist,
	isAbsoluteURL,
	getAbsolutePath,
	arrayToVector3,
	blink,
	resetBlink,
	vector3Offset,
	lngLatToVector3,
	getAttribute,
	getArrayDimensional,
	throttle,
	calculatingTargetPoints,
	getRectangleInfo,
	getTestHeight,
	calculateDistance,
	setTileset,
	getFloor,
	computeCenterPoint,
	moveFloor,
	resetFloor,
	vector3ToGeoPoint,
	worldToScreen,
	getGeoPointDistance,
	_offsetToposition
}
